<?php
declare(strict_types=1);

namespace app\data\model;

use app\data\api\ApiModel;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

/**
 *
 * @package app\data\model
 */
class BaseModel extends Model implements ApiModel
{
    protected $table = '';
    protected $schema = [];
    protected array $existField = [];

    public function __construct(array $data = [])
    {
        parent::__construct($data);
    }

    public function subBegin()
    {
        return $this->startTrans();
    }

    public function subCommit()
    {
        return $this->commit();
    }

    public function subRollback()
    {
        return $this->rollback();
    }

    /**
     *
     * 验证字段值是否已存在，不存在返回false,存在返回提示
     *
     * @param array $where ['app_key'=>'432aaaa']
     * @param array $other ['uid',4],['mid',7],['cid',8]
     * @return string|bool
     */
    public function validFieldExist(array $where, array $other = []): string|bool
    {

        $condition = array_intersect_key($where, $this->existField);

        if (empty($condition)) {
            return false;
        }

        foreach ($condition as $item => $val) {
            if ($other) {
                $ret = $this
                    ->where($other[0], '=', $other[1])
                    ->where($item, '=', $val)
                    ->count();
            } else {
                $ret = $this->where($item, '=', $val)->count();
            }
            if ($ret > 0) {
                return $this->existField[$item] . '已存在,规则：不能重复';
            }
        }

        return false;
    }

    /**
     *
     * title 新增一条数据
     *
     * @param array $data 新增数组
     * @return int 成功返回新增id,失败返回false
     */
    public function add(array $data): int
    {
        $standard = [
            'create_time' => time(),
            'update_time' => time(),
            'delete_time' => 0,
            'ver' => 0,
        ];

        $save = array_merge($data, $standard);

        return $this->strict(false)->insert($save, true);
    }

    /**
     *
     * title 新增一条数据
     *
     * @param array $data 新增数组
     * @return int 成功返回新增id,失败返回false
     */
    public function addInfo(array $data): int
    {
        $standard = [
            'create_time' => time(),
            'update_time' => time(),
            'delete_time' => 0,
            'ver' => 0,
        ];

        $save = array_merge($data, $standard);

        return $this->strict(false)->insertGetId($save);
    }

    /**
     *
     * title 新增多条数据
     *
     * @param array $data 新增数据
     * @return int 成功返回新增条数，失败返回0
     * @throws \Exception
     */
    public function addAll(array $datas): int
    {
        for ($i = 0; $i < count($datas); $i++) {
            $standard = [
                'create_time' => time(),
                'update_time' => time(),
                'delete_time' => 0,
                'ver' => 0,
            ];
            $datas[$i] = array_merge($datas[$i], $standard);
        }
        return $this->strict(false)->insertAll($datas);
    }

    /**
     *
     * title  编辑
     *
     * @param array $where 判断条件
     * @param array $data 更新数组
     * @param bool $lock 是否启用乐观锁，true 启用，false 不启用。默认false
     * @return int|bool 成功返回更新条数，失败返回0
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function edit(array $where, array $data, bool $lock = false): int|bool
    {
        $data['update_time'] = time();

        if ($lock) {
            $find = $this
                ->where($where)
                ->where('delete_time', '=', 0)
                ->field('ver')
                ->find()
                ->toArray();

            return $this
                ->where($where)
                ->where('ver', '=', $find['ver'])
                ->where('delete_time', '=', 0)
                ->strict(false)
                ->data($data)
                ->save();
        }

        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->strict(false)
            ->data($data)
            ->save();

    }

    /**
     *
     * title 编辑多条数据
     *
     * @param array $data 编辑数组参数
     * @return Collection 返回集合体
     * @throws \Exception
     */
    public function editAll(array $data): Collection
    {
        return $this->saveAll($data);
    }

    /**
     *
     * title 物理删除
     *
     * @param array $where 删除条件
     * @return int|bool 成功返回删除条数 失败返回0
     */
    public function del(array $where): int|bool
    {
        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->delete();
    }


    /**
     *
     * title  软删除，只更新删除字段
     *
     * @param array $where
     * @return int|bool
     */
    public function softDel(array $where = []): int|bool
    {
        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->data(['delete_time' => time(), 'update_time' => time()])
            ->save();
    }

    /**
     *
     * 获取一条数据
     *
     * @param array $where 查询条件
     * @param string $field 查询字段
     * @return array 返回数组数据
     */
    public function findOne(array $where = [], string $field = '*', array $with = []): array
    {
        $stmt = $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->field($field);
        if ($with) {
            $stmt = $stmt->with($with);
        }
        return $stmt
            ->findOrEmpty()
            ->toArray();
    }

    /**
     *
     * 获取多条数据
     *
     * @param array $where 查询条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @return array 返回数组数据
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function findAll(array $where = [], string $field = '*', string $order = '', array $with = []): array
    {
        $stmt = $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->field($field);
        if ($with) {
            $stmt = $stmt->with($with);
        }
        return $stmt
            ->order($order)
            ->select()
            ->toArray();
    }


    /**
     *
     * 获取数据条数
     *
     * @param array $where 查询条件
     * @return int 返回数据总数
     */
    public function total(array $where): int
    {
        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->count();
    }

    /**
     *
     * 分页查询，后台使用
     *
     * @param int $page_index 第几页
     * @param int $page_size 每页几条数据
     * @param array $where 查询条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @param array $withs 关联查询
     * @return array 返回数组数据
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function pages(int $page_index = 1, int $page_size = 10, array $where = [], string $field = '*', string $order = '', array $withs = []): array
    {
        $count = $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->count();


        $start = $page_size * ($page_index - 1);
        $stmt = $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->field($field)
            ->order($order)
            ->limit($start, $page_size);
        if (count($withs) > 0) {
            $stmt = $stmt->with($withs);
        }
        $data = $stmt
            ->select()
            ->toArray();

        $totalPage = $count % $page_size == 0 ? $count / $page_size : ceil($count / $page_size);

        return [
            'page_index' => $page_index + 1,
            'count' => $count,
            'list' => $data,
            'totalPage' => intval($totalPage),
            'pageInfo' => [
                'pageIndex' => $page_index,
                'pageSize' => $page_size,
                'totalPage' => $totalPage,
                'total' => $count,
            ]
        ];
    }

    /**
     *
     * 分页查询，瀑布流分页，提供最后数据id
     *
     * @param int $max_id 最后一条数据的id
     * @param int $page_size 每页几条数据
     * @param array $where 查询条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @return array 返回数组数据
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function paging(int $max_id = 1, int $page_size = 10, array $where = [], string $field = '*', string $order = ''): array
    {
        return $this
            ->where('id', '>', $max_id)
            ->where($where)
            ->where('delete_time', '=', 0)
            ->field($field)
            ->order($order)
            ->limit($page_size)
            ->select()
            ->toArray();
    }

    /**
     *
     * 关联查询，两个表的关联数据
     *
     * @param array $where 查询条件
     * @param string $table 主表
     * @param string $joinTable 子表
     * @param string $on 关联条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @return array 返回数组数据
     */
    public function joinData(array $where = [], string $table = '', string $joinTable = '', string $on = '', string $field = '*', string $order = ''): array
    {
        return $this
            ->table($table)
            ->alias('a')
            ->where($where)
            ->where('a.delete_time', '=', 0)
            ->where('b.delete_time', '=', 0)
            ->field($field)
            ->order($order)
            ->join("$joinTable b", "$on")
            ->select()
            ->toArray();
    }

    /**
     *
     * 关联分页，两个表的关联分页数据
     *
     * @param int $page_index 第几页
     * @param int $page_size 每页几条数据
     * @param array $where 查询条件
     * @param string $table 主表
     * @param string $joinTable 子表
     * @param string $on 关联条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @return array 返回数组数据
     */
    public function joinPage(int $page_index = 1, int $page_size = 10, array $where = [], string $table = '', string $joinTable = '', string $on = '', string $field = '*', string $order = ''): array
    {

        $count = $this
            ->table($table)
            ->alias('a')
            ->where($where)
            ->where('a.delete_time', '=', 0)
            ->field($field)
            ->order($order)
            ->join("$joinTable b", "$on")
            ->count();


        if ($count > $page_size) {
            $start = $page_size * ($page_index - 1);
            $data = $this
                ->table($table)
                ->alias('a')
                ->where($where)
                ->where('a.delete_time', '=', 0)
                ->where('b.delete_time', '=', 0)
                ->field($field)
                ->order($order)
                ->join("$joinTable b", "$on")
                ->limit($start, $page_size)
                ->select()
                ->toArray();

        } else {
            $data = $this
                ->table($table)
                ->alias('a')
                ->where($where)
                ->where('a.delete_time', '=', 0)
                ->where('b.delete_time', '=', 0)
                ->field($field)
                ->order($order)
                ->join("$joinTable b", "$on")
                ->select()
                ->toArray();
        }

        return [
            'count' => $count,
            'list' => $data
        ];
    }

    /**
     *
     * 关联分页查询，瀑布流分页，提供最后一条数据id
     *
     * @param int $page_size 每页几条数据
     * @param array $where 查询条件
     * @param string $table 主表
     * @param string $joinTable 子表
     * @param string $on 关联条件
     * @param string $field 查询字段
     * @param string $order 排序字段
     * @return array 返回数组数据
     */
    public function joinPaging(int $page_size = 10, array $where = [], string $table = '', string $joinTable = '', string $on = '', string $field = '*', string $order = ''): array
    {

        return $this
            ->table($table)
            ->alias('a')
            ->where($where)
            ->where('a.delete_time', '=', 0)
            ->where('b.delete_time', '=', 0)
            ->field($field)
            ->order($order)
            ->join("$joinTable b", "$on")
            ->limit($page_size)
            ->select()
            ->toArray();
    }

    /**
     *
     * 自增数据
     *
     * @param array $where
     * @param string $field
     * @param int $step
     * @return int 成功返回1，失败返回0
     */
    public function incr(array $where, string $field, int $step = 1): int
    {
        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->inc($field, $step)
            ->update();

    }

    /**
     *
     * 自减数据
     *
     * @param array $where
     * @param string $field
     * @param int $step
     * @return int  成功返回1，失败返回0
     * @throw DbException
     */
    public function decr(array $where, string $field, int $step = 1): int
    {
        return $this
            ->where($where)
            ->where('delete_time', '=', 0)
            ->dec($field, $step)
            ->update();

    }

}
